﻿using Hx.ADSyncPlatform.ActiveDirectory;
using Hx.ADSyncPlatform.ActiveDirectory.Model;
using Hx.ADSyncPlatform.Controllers.Base;
using Hx.ADSyncPlatform.Infrastructure.Exceptions;
using Hx.ADSyncPlatform.WebApi.Model;
using Hx.ADSyncPlatform.WebApi.Rpc;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Hx.ADSyncPlatform.Controllers
{
    /// <summary>
    /// 计算机控制器
    /// </summary>
    [Route("api/ad/personalComputer")]
    [Authorize]
    [ApiController]
    public class PersonalComputerController : BaseController
    {
        private ActiveDirectoryClient activeDirectoryClient;

        private SystemConfig systemConfig;

        private RpcConfig rpcConfig;

        private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

        /// <summary>
        /// 
        /// </summary>
        /// <param name="serviceProvider"></param>
        /// <param name="activeDirectoryClient"></param>
        public PersonalComputerController(IOptions<SystemConfig> myOptionsAccessor
            , IOptions<RpcConfig> rpcConfigAccessor, IServiceProvider serviceProvider, ActiveDirectoryClient activeDirectoryClient) : base(serviceProvider)
        {
            this.activeDirectoryClient = activeDirectoryClient;
            this.systemConfig = myOptionsAccessor.Value;
            this.rpcConfig = rpcConfigAccessor.Value;
            this.activeDirectoryClient.BeforeCreatePrivateComputer = InvokeRpcSyncComputer;

        }





        #region 个人计算机管理


        /// <summary>
        /// 个人计算机管理 列表 返回值 {default:{},private:[],public:[]}
        /// </summary>
        /// <returns></returns>
        [HttpGet("list")]
        public async Task<Result<Dictionary<string, object>>> List()
        {
            string account = base.platManager.Name;
            Person adPerson = activeDirectoryClient.Persons.Single(account);
            Computer defaultComputer = null;
            Dictionary<string, object> result = new Dictionary<string, object>();

            string workStations = adPerson.UserWorkstations;
            //logger.Info($"account:{account},workStations:{workStations}");
            if (string.IsNullOrEmpty(workStations))
            {
                result.Add("loginType", "all");//账户登陆计算机方式  尽可以登陆指定计算机
                return await Success<Dictionary<string, object>>(result);
            }
            (List<Computer> privateComputers, List<Computer> publicComputers) = this.activeDirectoryClient.ResolveComputers(adPerson, systemConfig);
            publicComputers = publicComputers.Where(n => n.Binded).ToList();//公共计算机只保留已绑定的

            result.Add("loginType", "appoint");
            result.Add("default", defaultComputer);
            result.Add("privateDatasource", privateComputers);
            result.Add("public", publicComputers);
            return await Success<Dictionary<string, object>>(result);

        }

        /// <summary>
        /// 个人计算机管理 绑定私人计算机 
        /// </summary>
        /// <returns></returns>
        [HttpPost("{samAccountName}/bind")]
        public async Task<Result<bool>> Bind([FromRoute] string samAccountName)
        {
            if (string.IsNullOrWhiteSpace(samAccountName))
            {
                throw new BizException("计算机名错误！");
            }
            string account = base.platManager.Name;


            Person adPerson = activeDirectoryClient.Persons.Single(account);
            string workStations = adPerson.UserWorkstations;
            if (string.IsNullOrEmpty(workStations))
            {
                throw new BizException("您的账号可以登陆所有计算机，无法解绑！");
            }
            List<string> computers = adPerson.UserWorkstations.Split(",").ToList();
            string bindComputerName = samAccountName.Replace("$", "").ToLower();

            computers.Add(bindComputerName);
            computers = computers.Distinct().ToList();
            Computer computer = activeDirectoryClient.Computers.Single(samAccountName);
            computer.Info = adPerson.SamAccountName;
            this.InvokeRpcSyncComputer(account, computers);

            activeDirectoryClient.Computers.Update(computer);

            adPerson.UserWorkstations = string.Join(",", computers);
            activeDirectoryClient.Persons.Update(adPerson);



            return await base.Success<bool>(true);


        }

        /// <summary>
        /// 个人计算机管理 解绑计算机 
        /// </summary>
        /// <returns></returns>
        [HttpPost("{samAccountName}/unbind")]
        public async Task<Result<bool>> UnBind([FromRoute] string samAccountName, string computerType = "personal")
        {
            string account = base.platManager.Name;
            Person adPerson = activeDirectoryClient.Persons.Single(account);
            string workStations = adPerson.UserWorkstations;
            if (string.IsNullOrEmpty(workStations))
            {
                throw new BizException("您的账号可以登陆所有计算机，无法解绑！");
            }

            List<string> computers = adPerson.UserWorkstations.Split(",").ToList();

            account = account.Replace(".", "-");
            if (account.Length > 12)
            {
                account = account.Substring(0, 12);
            }
            List<string> privateComputers = computers.Where(n => this.activeDirectoryClient.IsPrivateComputer(n,account,true)).ToList();

            if (privateComputers.Count == 1)
            {
                throw new BizException("不可以解绑所有私人计算机，至少保留一个！");
            }
            string unbindComputerName = samAccountName.Replace("$", "").ToLower();

            computers.Remove(unbindComputerName);
            switch (computerType)
            {
                case "personal": //私有计算机 需要清空计算机的info属性
                    {
                        //Computer computer = activeDirectoryClient.Computers.Single(samAccountName);
                        //computer.Info = "";
                        //activeDirectoryClient.Computers.Update(computer);
                        break;
                    }
                case "public":
                    {
                        break;
                    }
            }
            if (!computers.Any())
                adPerson.UserWorkstations = null;
            else
                adPerson.UserWorkstations = string.Join(",", computers);

#if !DEBUG

#endif
            this.InvokeRpcSyncComputer(base.platManager.Name, computers);
            activeDirectoryClient.Persons.Update(adPerson);

            return await base.Success<bool>(true);


        }

        /// <summary>
        /// 个人计算机管理 创建私人计算机
        /// </summary>
        /// <returns></returns>
        [HttpPost("addPersonComputer")]
        public async Task<Result> AddPersonComputer()
        {
            string account = base.platManager.Name;
            Person adPerson = activeDirectoryClient.Persons.Single(account);
            this.activeDirectoryClient.CreatePersonalComputer(adPerson, systemConfig.personComputer);
            //this.createPersonalComputer(adPerson);
            return await base.Success();
        }

        /// <summary>
        /// 删除计算机
        /// </summary>
        /// <param name="samAccountName"></param>
        /// <returns></returns>
        [HttpDelete("{samAccountName}/delete")]
        public async Task<Result> Delete(string samAccountName)
        {
            Computer computer = activeDirectoryClient.Computers.Single(samAccountName);
            if (computer == null) throw new BizException("不存在该计算机,请刷新系统界面！");
            if (!string.IsNullOrEmpty(computer.Info))//私人计算机
            {
                Person computerOwner = activeDirectoryClient.Persons.Single(computer.Info);
                if (computerOwner != null)
                {
                    if (!string.IsNullOrEmpty(computerOwner.UserWorkstations))
                    {
                        List<string> computerNames = new List<string>();  //计算机列表
                        computerNames = computerOwner.UserWorkstations.Split(",").ToList();
                        string personAccount = computerOwner.SamAccountName + "c";
                        if (personAccount.Length > 12)
                        {
                            personAccount = personAccount.Substring(0, 12);
                        }
                        computerNames.RemoveAll(n => n == personAccount);
                        computerOwner.UserWorkstations = string.Join(",", computerNames);
#if !DEBUG
 
#endif
                        this.InvokeRpcSyncComputer(computer.Info, computerNames);
                        activeDirectoryClient.Persons.Update(computerOwner);
                    }
                }
            }
            activeDirectoryClient.Computers.Delete(samAccountName);
            return await base.Success();


        }
        #endregion


        #region 公共方法


        /// <summary>
        /// 调用远程接口同步计算机
        /// </summary>
        /// <param name="account"></param>
        /// <param name="computers">计算机列表</param>
        /// <returns></returns>
        private void InvokeRpcSyncComputer(string account, List<string> computers)
        {
            RpcClient rpcClient = new RpcClient(this.rpcConfig);
            List<string> otherComputers = activeDirectoryClient.GetOtherComputers(account, computers);

            string otherComputersStr = "";
            if (otherComputers != null)
            {
                otherComputersStr = string.Join(",", otherComputers);
            }
            RpcResponse response = rpcClient.SyncComputer(account, otherComputersStr);
            if (response.Code != "200")
            {
                throw new Exception($"远程接口调用失败，详细信息：${response.Msg}");
            }
        }
        #endregion
    }
}
